from decimal import Decimal
from django_redis import get_redis_connection
from rest_framework import serializers
from django.utils import timezone
from django.db import transaction
import time

from goods.models import SKU
from orders.models import OrderInfo, OrderGoods


class CartSKUSerializer(serializers.ModelSerializer):
    count = serializers.IntegerField(label="数量")
    class Meta:
        model = SKU
        fields = ["id", "name", "default_image_url", "price", "count"]


class OrderGoodsSerializer(serializers.Serializer):
    freight = serializers.DecimalField(label='运费', max_digits=10 , decimal_places=2)
    skus = CartSKUSerializer(many=True)


class CommitOrderSerializer(serializers.ModelSerializer):
    """
    提交订单序列化器
    """
    class Meta:
        model = OrderInfo
        fields = ["order_id", "address", "pay_method"]
        extra_kwargs = {
            "order_id": {
                "read_only": True
            },
            "address": {
                "write_only": True,
                "required": True
            },
            "pay_method": {
                "write_only": True,
                "required": True
            },
        }

    def create(self, validated_data):
        """
        下单数据序列化器
        :param validated_data:
        :return:
        """
        # 获取当前下单用户
        user = self.context["request"].user
        # 生成订单编号
        order_id = timezone.localtime().strftime('%Y%m%d%H%M%S') + ("%09d" % user.id)

        # 保存订单基本信息数据 OrderInfo
        # 获取校验之后的地址和⽀付⽅式
        address = validated_data.get("address")
        pay_method = validated_data.get("pay_method")

        status = (OrderInfo.ORDER_STATUS_ENUM["UNPAID"]
                  if pay_method==OrderInfo.PAY_METHODS_ENUM["ALIPAY"]
                  else OrderInfo.ORDER_STATUS_ENUM["UNSEND"])

        #开启一个事物
        with transaction.atomic():
            # 创建回滚点
            savepoint = transaction.savepoint()
            try:
                # 保存订单基本信息 OrderInfo
                order = OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address=address,
                    total_count=0,
                    total_amount=Decimal('0'),
                    freight=Decimal('10.00'),
                    pay_method=pay_method,
                    status=status

                )
                # 从redis中获取购物车结算商品数据
                redis_con = get_redis_connection("carts")
                cart_dict = redis_con.hgetall("cart_%s" % user.id)
                cart_selected = redis_con.smembers("selected_%s" % user.id)

                order_dict = {}
                # 遍历结算商品：
                for sku_id in cart_selected:
                    order_dict[int(sku_id)] = int(cart_dict[sku_id])

                for sku_id, count in order_dict.items():
                    while True:
                        sku = SKU.objects.get(id=sku_id)

                        origin_stock = sku.stock
                        origin_sales = sku.sales
                        # 判断商品库存是否充足
                        if count > origin_stock:
                            raise serializers.ValidationError("库存不⾜")
                        # 减少商品库存，增加商品销量
                        #     sku.stock -= count
                        #     sku.sales += count
                        #     sku.save()
                        #增加乐观锁
                        # 测试增加时间
                        # time.sleep(5)
                        new_stock = origin_stock-count
                        new_sales = origin_sales+count
                        result = SKU.objects.filter(id=sku_id, stock=origin_stock).update(stock=new_stock, sales=new_sales)
                        # 增加一个判断一直抢购
                        if result==0:
                            continue
                        sku.goods.sales += count
                        sku.goods.save()
                    # 保存订单商品数据
                        OrderGoods.objects.create(
                            order=order,
                            sku=sku,
                            count=count,
                            price=sku.price
                        )
                        order.total_count += count
                        order.total_amount += (sku.price * count)
                        break


                order.total_count += order.freight
                order.save()
            except Exception:
                transaction.savepoint_rollback(savepoint)
                raise

            transaction.savepoint_commit(savepoint)

            # 在redis购物车中删除已计算商品数据
            # pl = redis_con.pipline()
            # pl.hdel('cart_%s' % user.id, *cart_selected)
            # pl.srem('selected_%s' % user.id, *cart_selected)
        return order



